﻿#region Header

// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------

#endregion

#region Usings

using System;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Reflection;

#endregion

namespace ScrumTable.Common.FileSystem
{
    /// <summary>
    /// Represents an utility class for the .NET FileInfo class.
    /// </summary>
    public static class FileInfoUtil
    {
        #region Declarations

        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------
        
        #endregion

        #region Constructors / Destructor

        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        #endregion

        #region Methods

        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new file with the given name and stores the data of the
        /// specified stream to the file system.
        /// </summary>
        /// <param name="filePath">Specifies the path of the file to store.</param>
        /// <param name="inputStream">Specifies the stream to write down. After the action the stream will be closed by this procedure.</param>
        public static void SaveStreamTo(string filePath, Stream inputStream)
        {
            DirectoryUtil.EnsureExists(Path.GetDirectoryName(filePath));

            using (FileStream fileToWrite = File.Create(filePath))
            {
                using (inputStream)
                {
                    // Fill the bytes[] array with the stream data 
                    byte[] bytesInStream = new byte[inputStream.Length];
                    inputStream.Read(bytesInStream, 0, bytesInStream.Length);

                    // Use FileStream object to write to the specified file 
                    fileToWrite.Write(bytesInStream, 0, bytesInStream.Length);
                }
            }
        }

        /// <summary>
        /// Returns a new file stream object which can be used to store data
        /// to the underlying system. If the file exists, it will be recreated.
        /// </summary>
        /// <param name="filePath">Specifies the path of the file to write its data down.</param>
        /// <returns>Returns a new file stream object which must be closed by the user.</returns>
        public static FileStream OpenNewForWriting(string filePath)
        {
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }
            return File.Open(filePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Write);
        }

        /// <summary>
        /// Creates a temporary copy of the current file and stores the
        /// temporary file into the global TEMP folder. Calling the Dispose
        /// method on the returning IDisposable object will delete the
        /// temporary copy.
        /// </summary>
        /// <param name="toCopy">Specifies the file info which contains the data to copy.</param>
        /// <param name="copy">Specifies the file info result object.</param>
        /// <returns>Returns the IDisposable object which can be used to delete the fileinfo object.</returns>
        public static IDisposable TemporaryCopy(this FileInfo toCopy, out FileInfo copy)
        {
            PreCondition.AssertNotNull(toCopy, "toCopy");

            DirectoryInfo directory = new DirectoryInfo(
                Path.Combine(Environment.GetEnvironmentVariable("TEMP"),
                Guid.NewGuid().ToString("D")));
            
            if (!directory.Exists)
            {
                directory.Create();
            }

            string tempFile = Path.Combine(directory.FullName, toCopy.Name);
            toCopy.CopyTo(tempFile, true);
            copy = new FileInfo(tempFile) { IsReadOnly = false };
            return new TempFileCopy(copy);
        }


        /// <summary>
        /// Checks if the file is unavailable (no access or not exist) by an other process 
        /// </summary>
        /// <param name="file">file info</param>
        /// <returns>true if file is unavailable (no access or not exist)</returns>
        [DebuggerStepThrough]
        public static bool IsFileLocked(this FileInfo file)
        {
            try
            {
                using (file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None))
                {
                    return false; //file is not locked      
                }
            }
            catch (IOException)
            {
                //the file is unavailable because it is:  
                //still being written to        
                //or being processed by another thread       
                //or does not exist (has already been processed)  
                return true;
            }
        }
        #endregion

        #region Events

        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion


        //--------------------------------------------------------------------
        // Nested Classes
        //--------------------------------------------------------------------

        private class TempFileCopy : IDisposable
        {
            #region Properties
            //--------------------------------------------------------------------
            // Properties
            //--------------------------------------------------------------------

            private readonly FileInfo _toDispose;

            #endregion

            #region Constructors / Destructor

            //--------------------------------------------------------------------
            // Constructors / Destructor
            //--------------------------------------------------------------------

            internal TempFileCopy(FileInfo toDispose)
            {
                _toDispose = toDispose;
            }

            #endregion

            #region Methods

            //--------------------------------------------------------------------
            // Methods
            //--------------------------------------------------------------------

            void IDisposable.Dispose()
            {
                if (_toDispose != null)
                {
                    _toDispose.Refresh();

                    if (_toDispose.Directory.Exists)
                    {
                        _toDispose.Directory.Delete(true);
                    }
                }
            }

            #endregion
        }
    }
}